#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json
import random
import time
import uuid

from common.common_models import QueryClusterResponse
from common.const import ExecuteResultEnum
from generaldb.gbase8a import LOGGER
from generaldb.gbase8a.commands.gbase_cmd import GbaseCmd
from generaldb.gbase8a.common.const import NormalErr, RegisterType, ErrorCode, JobType
from generaldb.gbase8a.service.base_service import MetaServiceWorker
from generaldb.gbase8a.service.resource.resource_service import GBaseInfos
from generaldb.gbase8a.util.gbase_util import GbaseUtil


class Resource(MetaServiceWorker):
    all_output = QueryClusterResponse(type='DataBase', sub_type='GeneralDb')

    def __init__(self, job_manager, param):
        super().__init__(job_manager, param)
        self.pid = job_manager.pid
        self.job_id = job_manager.job_id
        self.gbase_cmd = GbaseCmd(pid=self.pid)

    def check_application(self):
        # 连通性校验
        if not GbaseUtil.check_service_status(self.gbase_cmd.get_os_user()):
            return self.update_action_result(code=ExecuteResultEnum.INTERNAL_ERROR,
                                             body_err_code=ErrorCode.ERR_DB_SERVICES,
                                             msg="Service not running!")
        code = ExecuteResultEnum.SUCCESS
        fun_inst = GBaseInfos(self.pid, self.gbase_cmd)
        ret, _ = fun_inst.check_auth()
        if ret != NormalErr.NO_ERR:
            LOGGER.error("error user info")
            return self.update_action_result(code=ExecuteResultEnum.INTERNAL_ERROR,
                                             body_err_code=ret.value,
                                             msg="Auth failed!")
        param_inst = self.param
        present_name = param_inst.get_present_database_name()
        vc_name = param_inst.get_vc_name()
        if fun_inst.is_skip_verify():
            LOGGER.info("Skip verification on this host!")
            return self.update_action_result(code)
        ret_list = [
            fun_inst.check_cluster_service(),
            fun_inst.check_database_exist(present_name, vc_name, param_inst),
            fun_inst.check_version()
        ]
        for ret, error_param in ret_list:
            if ret != NormalErr.NO_ERR:
                return self.update_action_result(code=ExecuteResultEnum.INTERNAL_ERROR,
                                                 body_err_code=ret.value,
                                                 err_param=error_param,
                                                 msg="Check application failed!")
        return self.update_action_result(code)

    def support_gbase_resource(self):
        """
        support resource接口
        :param
        :return: 没有返回值，返回值直接写入到对应的结果文件
        """
        # 自定义参数
        fun_inst = GBaseInfos(self.pid, self.gbase_cmd)
        if not GbaseUtil.check_service_status(self.gbase_cmd.get_os_user()):
            self.update_result_when_support_resource_error(ErrorCode.ERR_DB_SERVICES, "Service not running!")
            return
        ret, _ = fun_inst.check_auth()
        if ret != NormalErr.NO_ERR:
            self.update_result_when_support_resource_error(ret.value, "Check application failed!")
            return
        result_param = self.param.get_param()
        protected_env = result_param.get("appEnv", {})
        if fun_inst.is_skip_verify():
            LOGGER.info("Skip verification on this host!")
            protected_env['extendInfo']['shouldNextSupport'] = True
            self.build_result(protected_env)
            return
        protected_env['extendInfo']['shouldNextSupport'] = False
        original_name = self.param.get_original_database_name()
        present_name = self.param.get_present_database_name()
        vc_name = self.param.get_vc_name()
        node_list = self.param.get_register_ip_list()
        deploy_type = self.param.get_deploy_type()
        fun_list = self.get_fun_list(deploy_type, fun_inst, node_list, present_name, vc_name)
        for fun, args in fun_list:
            ret, error_param = fun(*args) if args is not None else fun()
            if ret != NormalErr.NO_ERR:
                LOGGER.error("Failed check connection!")
                self.update_result_when_support_resource_error(ret.value, "Check application failed!", error_param)
                return
        LOGGER.info("Support resource check application success with pid %s.", self.pid)

        # 修改数据库资源时，不允许修改数据库名称
        if original_name and RegisterType.DATABASE == self.param.get_instance_or_database() \
                and original_name != present_name:
            LOGGER.info("Rename database name is forbidden.")
            self.update_result_when_support_resource_error(ErrorCode.ERR_RENAME_DATABASE.value,
                                                           "Rename database name is forbidden.")
            return

        # 设置version
        code, version = fun_inst.get_version()
        protected_env['extendInfo']['applicationVersion'] = version
        if self.param.get_register_or_change() == JobType.REGISTER:
            protected_env["id"] = str(uuid.uuid5(uuid.NAMESPACE_X500, "gbase8a" + self.param.get_vc_name() +
                                                 str(random.randint(0, 100000000000)) +
                                                 str(int(round(time.time() * 1000)))))
        # 设置集群信息
        protected_env['extendInfo']['cluster_info'] = json.dumps(fun_inst.get_all_nodes_info())
        self.build_result(protected_env)

    def get_fun_list(self, deploy_type, fun_inst, node_list, present_name, vc_name):
        fun_list = [
            (fun_inst.check_sys_user, None),
            (GBaseInfos.check_deploy_type, (deploy_type,)),
            (fun_inst.check_version, None),
            (fun_inst.check_nodes_topo, (node_list,)),
            (fun_inst.check_environment, None),
            (fun_inst.check_database_exist, (present_name, vc_name, self.param)),
            (fun_inst.check_database_engine, (present_name, vc_name))
        ]
        return fun_list

    def build_result(self, protected_env):
        resource_json = {"resourceList": [protected_env]}
        self.job_manager.update(resource_json)

    def update_result_when_support_resource_error(self, error_code, msg, error_params=None):
        if error_params is None:
            error_params = []
        result = {"exception": {"code": error_code, "message": msg, "codeParams": error_params}}
        self.job_manager.update(result)
